package com.beidasoft.flip.webframe.core.jpa;

import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.lang.NonNull;
import org.springframework.transaction.annotation.Transactional;

import com.beidasoft.flip.webframe.core.pojo.DO;
import com.beidasoft.flip.webframe.core.pojo.DTO;
import com.beidasoft.flip.webframe.core.repository.FlipJpaRepository;
import com.beidasoft.flip.webframe.core.util.CommonUtil;

/**
 * <p>FlipJpaRepository接口的实现类，该类主要提供拓展的公用方法，同时满足FlipJpaRepository接口的继承接口的代理类的实现</p>
 * @author 肖翔
 * @date 2019/12/04
 */
@Transactional(readOnly = true)
public class FlipJpaRepositoryImpl<T extends DO, ID> extends SimpleJpaRepository<T, ID>
    implements FlipJpaRepository<T, ID> {

    /**
     * <p>实体类的数据操作的对象</p> 
     */
    private final EntityManager entityManager;

    /**
     * <p>字段映射，类型转化</p>
     * @param t
     * @param s
     * @return
     */
    private <S extends DTO> S copyPropeyties(T t, S s) {
        return CommonUtil.copyPropeyties(t, s);
    }

    /**
     * <p>构造方法</p>
     * @param domainClass 实体类的Class
     * @param em 实体类的数据操作的对象
     */
    public <S extends DTO> FlipJpaRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
        super(domainClass, entityManager);
        this.entityManager = entityManager;
    }

    /* (non-Javadoc)
     * @see com.beidasoft.flip.webframe.repository.FlipJpaRepository#findAll2DTO(org.springframework.data.domain.Pageable)
     */
    @SuppressWarnings("unchecked")
    @Override
    public <S extends DTO> Page<S> findAll2DTO(Pageable pageable, @NonNull Class<S> clazz, Object... constructFields) {
        //查询到所有的结果
        Page<T> page = findAll(pageable);
        return page.map(t -> {
            S tmp = CommonUtil.newInstance(clazz, constructFields);
            return copyPropeyties(t, tmp);
        });
    }

    /* (non-Javadoc)
     * @see com.beidasoft.flip.webframe.repository.FlipJpaRepository#findAll2DTO()
     */
    @SuppressWarnings("unchecked")
    @Override
    public <S extends DTO> List<S> findAll2DTO(@NonNull Class<S> clazz, Object... constructFields) {
        List<T> list = findAll();
        return list.stream().map(t -> {
            S tmp = CommonUtil.newInstance(clazz, constructFields);
            return copyPropeyties(t, tmp);
        }).collect(Collectors.toList());
    }

    /* (non-Javadoc)
     * @see com.beidasoft.flip.webframe.repository.FlipJpaRepository#find2DTO(org.springframework.data.domain.Example, org.springframework.data.domain.Pageable)
     */
    @Override
    public <S extends DTO> Page<S> find2DTO(Example<T> example, Pageable pageable, S s) {
        Page<T> page = findAll(example, pageable);
        return page.map(t -> {
            return copyPropeyties(t, s);
        });
    }

    /* (non-Javadoc)
     * @see com.beidasoft.flip.webframe.repository.FlipJpaRepository#find2DTO(org.springframework.data.domain.Example)
     */
    @Override
    public <S extends DTO> List<S> find2DTO(Example<T> example, S s) {
        List<T> list = findAll(example);
        return list.stream().map(t -> {
            return copyPropeyties(t, s);
        }).collect(Collectors.toList());
    }

    /* (non-Javadoc)
     * @see com.beidasoft.flip.webframe.repository.FlipJpaRepository#findAll2DTOById(java.lang.Iterable)
     */
    @SuppressWarnings("unchecked")
    @Override
    public <S extends DTO> List<S> findAll2DTOById(Iterable<ID> ids, @NonNull Class<S> clazz,
        Object... constructFields) {
        List<T> list = findAllById(ids);
        return list.stream().map(t -> {
            S tmp = CommonUtil.newInstance(clazz, constructFields);
            return copyPropeyties(t, tmp);
        }).collect(Collectors.toList());
    }

    /* (non-Javadoc)
     * @see com.beidasoft.flip.webframe.repository.FlipJpaRepository#find2DTOById(java.lang.Object)
     */
    @Override
    public <S extends DTO> Optional<S> find2DTOById(ID id, S s) {
        Optional<T> t = findById(id);
        return t.map(tmp -> {
            return copyPropeyties(tmp, s);
        });
    }

    /* (non-Javadoc)
     * @see com.beidasoft.flip.webframe.repository.FlipJpaRepository#executeSql(java.lang.String, java.lang.Iterable)
     */
    @Transactional
    @Override
    public List<?> executeSqlQuery(String sql, Iterable<T> values) {
        Query query = entityManager.createNativeQuery(sql);
        int i = 0;
        Iterator<T> iterator = values.iterator();
        while (iterator.hasNext()) {
            query.setParameter(i++, iterator.next());
        }
        return query.getResultList();
    }

    /* (non-Javadoc)
     * @see com.beidasoft.flip.webframe.repository.FlipJpaRepository#executeHql(java.lang.String, java.lang.Iterable)
     */
    @Transactional
    @Override
    public int executeSqlUpdate(String sql, Iterable<T> values) {
        Query query = entityManager.createNativeQuery(sql);
        int i = 0;
        Iterator<T> iterator = values.iterator();
        while (iterator.hasNext()) {
            query.setParameter(i++, iterator.next());
        }
        return query.executeUpdate();
    }

}
